<template>
  <form class="page page-important-info">
    <h4 class="text-center">本地敏感信息检查</h4>
    <div class="alert alert-info">
      部分检查项目虽然存在，但可能因注册表权限限制无法获取到，可根据注册表地址自行查看。
    </div>
    <fieldset class="page-body">
      <legend>数据列表</legend>
      <div class="fieldset-inner">
        <div class="table-wrapper">
          <div class="table-header" :style="thStyles">
            <table>
              <tbody>
                <tr>
                  <th v-for="(v,i) in tableHeaders" :key="`th_${i}`" :style="{width: v.width}">{{v.label}}</th>
                </tr>
              </tbody>
            </table>
          </div>
          <div class="table-body">
            <table ref="table">
              <tbody>
                <tr v-for="(v,i) in dataList" :key="`tr_${i}`">
                  <template v-for="(item,index) in tableHeaders">
                    <td :style="{width: item.width}" :key="`td_${i}_${index}`">
                      <div v-if="item.value==='data'" class="text-left">
                        <div v-for="(rData,rIndex) in (v.data || [])" :key="`r_${rIndex}`">{{rData}}</div>
                      </div>
                      <div v-else-if="item.value==='path'" :title="v[item.value] || ''"
                      class="text-grey text-left">{{v[item.value] || ''}}</div>
                      <div v-else-if="item.value==='exists'">{{v[item.value] ? '是' : ''}}</div>
                      <div v-else>{{v[item.value] || ''}}</div>
                    </td>
                  </template>
                </tr>
                <tr v-if="dataList.length===0" class="nodata-tr"><td>暂无数据</td></tr>
              </tbody>
            </table>
          </div>
        </div>
        <x-loading size="large" fix v-if="loadingCount > 0"></x-loading>
      </div>
    </fieldset>
    <div class="page-footer">
      <x-button type="primary" block :loading="loadingCount > 0" @click="getDataList">重新获取</x-button>
    </div>
  </form>
</template>

<script>
const iconv = require('iconv-lite')
const {exec} = global.require('child_process')
let regedit = global.regedit || null
let regeditPromisified = global.regeditPromisified || null
let {debounce}  = global.$jstools || {}
// 待检查列表
// eslint-disable-next-line no-prototype-builtins
let jyktPath = (process.arch === 'x64' || process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432')) ?
  'HKLM\\SOFTWARE\\WOW6432Node\\TopDomain\\e-Learning Class\\Teacher' : 'HKLM\\SOFTWARE\\TopDomain\\e-Learning Class\\Teacher'
let regsList = [
  {name: '极域课堂 v6', regPath: jyktPath, regItems: [], mark: 'jykt'},
  {name: 'PcAnyWhere', regPath: 'HKLM\\SOFTWARE\\Symantec\\pcAnywhere\\CurrentVersion\\System', regItems: [
    {value: 'TCPIPDataPort', label: '数据端口'},
    {value: 'TCPIPStatusPort', label: '状态端口'},
  ]},
  {name: 'Radmin v2', regPath: 'HKLM\\SYSTEM\\RAdmin\\v2.0\\Server\\Parameters', regItems: [
    {value: 'Parameter', label: '密码'},
    {value: 'Port', label: '端口'},
  ]},
  {name: 'RealVNC v3', regPath: 'HKCU\\Software\\ORL\\WinVNC3', regItems: [
    {value: 'Password', label: 'HEX密文'},
    {value: 'PortNumber', label: '端口'},
  ]},
  {name: 'RealVNC v4', regPath: 'HKCU\\SOFTWARE\\RealVNC\\WinVNC4', regItems: [
    {value: 'Password', label: 'HEX密文'},
    {value: 'PortNumber', label: '端口'},
  ]},
  {name: 'RealVNC v6', regPath: 'HKLM\\SOFTWARE\\RealVNC\\vncserver', regItems: [
    {value: 'Password', label: 'HEX密文'},
    {value: 'RfbPort', label: '端口'},
  ], func: 'getRegData'},
  {name: 'UltraVNC', regPath: 'HKLM\\SOFTWARE\\ORL\\WinVNC3\\Default', regItems: [
    {value: 'password', label: 'HEX密文'},
  ]},
  {name: 'TigerVNC v4', regPath: 'HKCU\\Software\\TigerVNC\\WinVNC4', regItems: [
    {value: 'Password', label: '密文'},
  ]},
  {name: 'TightVNC v2.8', regPath: 'HKLM\\SOFTWARE\\TightVNC\\Server', regItems: [
    {value: 'Password', label: '密文1'},
    {value: 'ControlPassword', label: '密文2'},
  ]},
  {name: 'TightVNC', regPath: 'HKCU\\Software\\TightVNC\\Server', regItems: [
    {value: 'Password', label: '密文1'},
    {value: 'PasswordViewOnly', label: '密文2'},
  ]},
  {name: 'WinPoET', regPath: 'HKLM\\SOFTWARE\\iVasion\\WinPoet\\Connections', regItems: [
    {value: '00,2 UserName', label: '用户名'},
    {value: '00,3 Password', label: '密文'},
  ]},
  {name: 'TCP/IP过滤1', regPath: 'HKLM\\SYSTEM\\ControlSet001\\Services\\Tcpip', regItems: [
    {value: 'EnableSecurityFilters', label: ''},
  ]},
  {name: 'TCP/IP过滤2', regPath: 'HKLM\\SYSTEM\\ControlSet002\\Services\\Tcpip', regItems: [
    {value: 'EnableSecurityFilters', label: ''},
  ]},
  {name: 'TCP/IP过滤3', regPath: 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip', regItems: [
    {value: 'EnableSecurityFilters', label: ''},
  ]},
  {name: 'Windows密钥', regPath: 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SoftwareProtectionPlatform', regItems: [
    {value: 'BackupProductKeyDefault', label: '密钥'},
  ], func: 'getWindowsSecretkey'},
  {name: '最近使用的软件', regPath: 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU', regItems: []},
  {name: '计划日志', regPath: 'HKLM\\SOFTWARE\\Microsoft\\SchedulingAgent', regItems: [
    {value: 'LogPath', label: '路径'},
  ]},
  {name: '网卡列表', regPath: 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage', regItems: [
    {value: 'Bind', label: ''},
  ]},
  {name: '远程桌面连接', regPath: 'HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp', regItems: [
    {value: 'PortNumber', label: '端口'},
  ]},
  {name: '防火墙开放端口', regPath: 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\StandardProfile\\GloballyOpenPorts\\List', regItems: [
    {value: '3389:TCP', label: ''},
  ]},
  {name: '允许的端口', regPath: 'HKLM\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces\\{8A465128-8E99-4B0C-AFF3-1348DC55EB2E}', regItems: [
    {value: 'UDPAllowedPorts', label: 'UDP端口'},
    {value: 'TCPAllowedPorts', label: 'TCP端口'},
  ]},
]

export default {
  name: 'important-info',
  data () {
    return {
      dataList: [],
      tableHeaders: [
        {label: '项目名称', value: 'name', width: '20%'},
        {label: '项目内容', value: 'data', width: '35%'},
        {label: '存储位置', value: 'path', width: '35%'},
        {label: '项目存在', value: 'exists', width: '10%'},
      ],
      thStyles: {},
      loadingCount: 0
    }
  },
  mounted () {
    window.addEventListener('resize', this.checkScroll)
    regedit = this.$sharedObject('regedit')
    regeditPromisified = regedit.promisified
    this.getDataList()
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.checkScroll)
  },
  methods: {
    // 获取项目数据
    getDataList () {
      this.dataList = []
      let regPaths = regsList.map(v => v.regPath)
      if (regPaths.length) {
        this.loadingCount++
        regeditPromisified.list(regPaths).then((res)=>{
          for (let k in res) {
            let v = res[k] || {}
            let i = regPaths.indexOf(k)
            // if (!v.exists) continue
            let values = v.values || {}
            let regItem = regsList[i]
            let rows = []
            if (regItem.mark === 'jykt') {
              let AccountCounts = (values.AccountCounts || {}).value || 0
              for (let j = 1; j <= AccountCounts; j++) {
                let userInfo = (values[`Account${j}`] || {}).value || []
                if (userInfo.length === 0) continue
                let username = Buffer.from(userInfo.slice(0, 64)).toString('utf16le')
                let password = Buffer.from(userInfo.slice(64)).toString('utf16le')
                let _username = decodeURI(encodeURI(username).replace(/%00/g, ''))
                let _password = decodeURI(encodeURI(password).replace(/%00/g, ''))
                rows.push(`${_username} / ${_password}`)
              }
            } else {
              regItem.regItems.forEach(item => {
                let val = values[item.value] || ''
                rows.push(`${item.label ? (item.label + ':') : ''}${val.value || ''}`)
              })
            }
            this.dataList.push({
              name: regItem.name, data: rows, path: regItem.regPath, exists: v.exists
            })
            // if (regItem.func) {
            //   this[regItem.func](regItem, i)
            // }
          }
        }).catch((err) => {
          console.log(err)
        }).finally(() => {
          this.loadingCount--
          this.checkScroll()
        })
      }
    },
    // 获取Windows秘钥
    getWindowsSecretkey (regItem, index) {
      let regPath = regItem.regPath
      let command = `chcp 65001 & REG QUERY "${regPath}" /v BackupProductKeyDefault`
      exec(command, (error, stdout, stderr) => {
        if (error) {
          // this.$toast('命令执行失败，请以管理员身份运行程序后重试')
          return
        }
        console.log(`stdout: ${stdout}`)
        console.error(`stderr: ${stderr}`)
        let str = iconv.decode(stdout, 'utf8') || ''
        let res = str.match(/\b([A-Z1-9]{5}-[A-Z1-9]{5}-[A-Z1-9]{5}-[A-Z1-9]{5}-[A-Z1-9]{5})\b/)
        res && this.$set(this.dataList[index], 'data', [res[1] || ''])
      })
    },
    // 使用Nodejs获取注册表信息
    getRegData (regItem, index) {
      let regPath = regItem.regPath
      let taskList = []
      regItem.regItems.forEach(v => {
        let command = `chcp 65001 & REG QUERY "${regPath}" /v ${v.value}`
        taskList.push(new Promise((resolve, reject) => {
          exec(command, (error, stdout, stderr) => {
            if (error) {
              reject(error)
            } else {
              console.log(`stdout: ${stdout}`)
              console.error(`stderr: ${stderr}`)
              let str = iconv.decode(stdout, 'utf8') || ''
              let idx = str.indexOf(v.value)
              let arr = str.substr(idx).trim().split(/\s+/)
              resolve(`${v.label ? (v.label + ':') : ''}${arr[arr.length - 1]}`)
            }
          })
        }).catch((err) => {console.log(err)}))
      })
      Promise.all(taskList).then((results) => {
        results && this.$set(this.dataList[index], 'data', results)
      })
    },
    // 修正滚动条
    checkScroll: debounce(function () {
      this.$nextTick(() => {
        if (!this.$refs.table) return
        let tableHeight = this.$refs.table.clientHeight
        let tableParentHeight = this.$refs.table.parentNode.clientHeight
        if (tableHeight > tableParentHeight) {
          this.thStyles = {overflow: 'hidden scroll'}
        } else {
          this.thStyles = {overflow: 'hidden'}
        }
      })
    })
  }
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
.page-important-info {
	display: flex;
	flex-direction: column;
	.page-body {
		height: 0;
		flex-grow: 1;
    .fieldset-inner {
      width: 100%;
      height: calc(100% - 2em);
      display: flex;
      overflow: hidden;
      position: relative;
    }
    .table-wrapper {
      width: 0;
      flex-grow: 1;
      transition: all .25s linear;
    }
    .table-header,
    .table-body {
      table {
        width: 100%;
        border: 1px solid @borderGrey;
        tr {height: 2em;}
        th, td {
          border: 1px solid @borderGrey;
          text-align: center;
          vertical-align: middle;
        }
        .nodata-tr {
          height: 100%;
          font-size: 16px;
          color: #999;
        }
      }
    }
    .table-body {
      height: calc(100% - 2em);
      overflow: auto;
      table {
        min-height: 100%;
      }
      tr {
        transition: all .2s linear;
        cursor: pointer;
      }
      tr.active {
        background-color: @bgGrey;
      }
      td {padding: .5em;}
    }
  }
  .page-footer {
    margin-top: 1em;
  }
}
</style>
